package com.netrust.cmsx.admin.modules.sys.service;


import java.util.Arrays;
import java.util.List;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Join;
import javax.persistence.criteria.JoinType;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.apache.commons.collections.Transformer;
import org.hibernate.criterion.Order;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.google.common.collect.Lists;
import com.netrust.cmsx.admin.modules.sys.common.AStatic;
import com.netrust.cmsx.admin.modules.sys.pojo.MenuPo;
import com.netrust.cmsx.admin.modules.sys.utils.UserUtils;
import com.netrust.cmsx.core.exception.ProvideException;
import com.netrust.cmsx.core.jpa.Criteria;
import com.netrust.cmsx.core.jpa.Restrictions;
import com.netrust.cmsx.core.jpa.Criterion.MatchMode;
import com.netrust.cmsx.core.page.PageKey;
import com.netrust.cmsx.core.persist.TreeUtil;
import com.netrust.cmsx.core.service.CrudService;
import com.netrust.cmsx.core.service.TreeService;
import com.netrust.cmsx.entity.module.sys.Dict;
import com.netrust.cmsx.entity.module.sys.Menu;
import com.netrust.cmsx.entity.module.sys.Role;
import com.netrust.cmsx.entity.module.sys.User;
import com.netrust.cmsx.persist.module.sys.MenuDao;
import com.netrust.cmsx.utils.collections.CollectionUtils;
import com.netrust.cmsx.utils.string.StringUtils;
import com.netrust.cmsx.utils.tree.Tree;


@Transactional(readOnly=true)
@Service("menuService")
public class MenuService extends CrudService<Menu,String,MenuDao>{
	@Autowired
	UserService userService;
	
	public List<Menu> findByUserId(String id) {
		final String fid=id;
		List<Menu> plist =dao.findAll(new Specification<Menu>() {
			public Predicate toPredicate(Root<Menu> root, CriteriaQuery<?> cq,CriteriaBuilder cb) {
				Join<Menu, Role> join=root.join(root.getModel().getList("roles", Role.class),JoinType.LEFT);
				Join<Role, User> join2=join.join("users",JoinType.LEFT);
				
				//凭证查询
				Predicate p = cb.equal(join2.get("id").as(Integer.class),fid);
				Predicate p1 = cb.equal(join2.get("delFlag").as(boolean.class),false);//查询未删除的
				
				cq.distinct(true);//去重。重要！多角色问题
				cq.where(cb.and(p,p1));
				
				return cq.getRestriction();
			}
		
		});
		
		return plist;
	}

	public List<Menu> findByUserId(String id,String type) {
		final String fid=id;
		final String ftype=type;
		List<Menu> plist =dao.findAll(new Specification<Menu>() {
			public Predicate toPredicate(Root<Menu> root, CriteriaQuery<?> cq,CriteriaBuilder cb) {
				Join<Menu, Role> join=root.join(root.getModel().getList("roles", Role.class),JoinType.LEFT);
				Join<Role, User> join2=join.join("users",JoinType.LEFT);
				
				//凭证查询
				Predicate p = cb.equal(join2.get("id").as(String.class),fid);
				Predicate p1 = cb.equal(root.get("delFlag").as(boolean.class),false);//查询未删除的

				cq.distinct(true);//去重。重要！多角色问题
				
				if(ftype!=null){
					Predicate p2 = cb.equal(root.get("type").as(String.class),ftype);//查询在类型
					cq.where(cb.and(p,p1,p2));					
				}else{
					cq.where(cb.and(p,p1));										
				}
				
				return cq.getRestriction();
			}
			
		});
		
		return plist;
	}
	
	public List<Menu> findByType(String type) {
		if(!AStatic.mtype_menu.equals(type)&&!AStatic.mtype_permission.equals(type)){
			return null;
		}
		
		Criteria<Menu> criteria=new Criteria<Menu>();
		criteria.add(Restrictions.eq("type",type));
		criteria.add(Restrictions.eq("delFlag",false));

		List<Menu> list=dao.findAll(criteria);
		return list;
	}
	
	
	//如果这段代码好用，那它是Lazite写的。
	//如果不好用，我不知道是谁写的。
	public List<Menu> findTopMenuByUserId(String id) {
		final String fid=id;
		List<Menu> plist =dao.findAll(new Specification<Menu>() {
			public Predicate toPredicate(Root<Menu> root, CriteriaQuery<?> cq,CriteriaBuilder cb) {
				Join<Menu, Role> join=root.join(root.getModel().getList("roles", Role.class),JoinType.LEFT);
				Join<Role, User> join2=join.join("users",JoinType.LEFT);
				
				//凭证查询
				Predicate p = cb.equal(root.get("delFlag").as(boolean.class),false);//查询未删除出
				Predicate p1 = cb.equal(root.get("isShow").as(boolean.class),true);//查询在首页显示的
				//Predicate p2 = cb.equal(root.get("parent").get("id").as(Integer.class),1);//查询顶级
				
				Predicate p3 = cb.equal(join2.get("id").as(Integer.class),fid);//查询用户权限的
				
				//Predicate p4 = cb.equal(root.get("type").as(String.class),"menu");//查询menu
				
				p=cb.and(p,p1,p3);
				
				cq.distinct(true);//去重。重要！多角色问题
				cq.where(p);
				return cq.getRestriction();
			}
		},new Sort(Direction.ASC, "sort"));
		
		return plist;
	}
	

	
	//菜单树
	public List<MenuPo> findTreeMenu4User(String uid){
	    List<Menu> menuList=this.findByUserId(uid,AStatic.mtype_menu);
		List<MenuPo> menuPos=Lists.newArrayList();
		for (Menu menu : menuList) {
			MenuPo mp=new MenuPo();
			
			BeanUtils.copyProperties(menu, mp,"parent","children");
			menuPos.add(mp);
		}
		
		List<MenuPo> mps=new TreeUtil<MenuPo>().getChildTree(menuPos,1);
		return mps;
	}
	
	//菜单树
	public List<MenuPo> findTreeMenuPoFromMenu(List<Menu> menuList){
		List<MenuPo> menuPos=Lists.newArrayList();
		for (Menu menu : menuList) {
			MenuPo mp=new MenuPo();
			
			BeanUtils.copyProperties(menu, mp,"parent","children");
			menuPos.add(mp);
		}
		List<MenuPo> mps=new TreeUtil<MenuPo>().getChildTree(menuPos,1);
		return mps;
	}
	
	@Transactional(readOnly=false)
	public void saveMenu(Menu menu) {
		if(StringUtils.isNotBlank(menu.getId())){
			Menu old=dao.findOne(menu.getId());
			try {
				//判断父节点是否循环调用
				@SuppressWarnings("unchecked")
				List<String> cids=CollectionUtils.extractToList(old.getChildren(), "id");
				
				if(AStatic.zero.equals(menu.getPid())){
					BeanUtils.copyProperties(menu, old,"children","delFlag");
					Menu parent=new Menu(AStatic.zero);
					old.setParent(parent);
					old.setPids(menu.getPid()+",");					
				}else{
					if(cids.contains(menu.getPid())){
						throw ProvideException.unchecked(new Exception("父节点  = "+menu.getPid()+" 设置不正确，循环调用造成数据混乱"));
					}
					BeanUtils.copyProperties(menu, old,"children","delFlag");
					Menu parent=dao.findOne(menu.getPid());
					old.setParent(parent);
					old.setPids(parent.getPids()+menu.getPid()+",");					
				}

				this.save(old);
			} catch (Exception e) {
				throw ProvideException.unchecked(e);
			}
			
		}else{
			menu.setDelFlag(false);
			Menu parent=new Menu(AStatic.zero);

			if(!AStatic.zero.equals(menu.getPid())){
				parent=dao.findOne(menu.getPid());
				menu.setPids(parent.getPids()+menu.getPid()+",");
			}else{				
				menu.setPids(menu.getPid()+",");
			}
			
			menu.setParent(parent);
			this.save(menu);
		}
	}
	
	
	@Transactional(readOnly=false)
	public void deleteInFlag(Menu menu) {
		if(menu!=null&&menu.getId()!=null){
			menu=dao.findOne(menu.getId());
			menu.setDelFlag(true);
			menu.setWhetherNew(false);
			this.save(menu);	
		}
	}

	public Page<Menu> findPermissionList(PageKey pk) {
		final String fpid=pk.getKey();
		Page<Menu> plist =dao.findAll(new Specification<Menu>() {
			public Predicate toPredicate(Root<Menu> root, CriteriaQuery<?> cq,CriteriaBuilder cb) {
				
				Predicate p = cb.equal(root.get("delFlag").as(boolean.class),false);//查询未删除出
				//凭证查询
				if(pk!=null&&pk.getKey()!=null){
					Predicate p1 = cb.equal(root.get("parent").get("id").as(String.class),fpid);//查询顶级
					p=cb.and(p,p1);
				}
				
				Predicate p2 = cb.equal(root.get("type").as(String.class),AStatic.mtype_permission);//查询permission
				p=cb.and(p,p2);
			
				cq.where(p);
				return cq.getRestriction();
			}
		},new PageRequest(pk.getPageNum(), pk.getPageSize(), new Sort(Direction.ASC,"name","sort")));
		
		return plist;
	}
}
